import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.util.AsciiString;
import net.sf.json.JSONObject;
import v1.grade.GradeService;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

public class GradeServerHandler extends ChannelInboundHandlerAdapter {
    private static final AsciiString CONTENT_TYPE = new AsciiString("Content-Type");
    private static final AsciiString CONTENT_LENGTH = new AsciiString("Content-Length");
    private static final AsciiString CONNECTION = new AsciiString("Connection");
    private static final AsciiString KEEP_ALIVE = new AsciiString("keep-alive");

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest req = (FullHttpRequest) msg;//客户端的请求对象
            String uri = req.uri();//获取客户端的URL

            System.out.println(req.method()+"\t"+uri);

            try {
                Map<String,String> urlMap = parseUrl(req);

//                for (String key : urlMap.keySet()) {
//                    System.out.println(key+"\t:"+urlMap.get(key));
//                }

                String p = urlMap.get("p");
                String requestJson = urlMap.get("context");
                if(p!=null && p.startsWith("app/grade/")){
                    String[] patterns = p.split("/");
                    String methodName = patterns[patterns.length-1];
                    try {
                        Method method = null;
                        Map<String,Method> methodMap = this.methodMapThreadLocal.get();
                        if(methodMap != null){
                            method = methodMap.get(methodName);
                        }else {
                            this.methodMapThreadLocal.set(new HashMap<String, Method>());
                        }

                        if(method==null){
                            method = GradeService.class.getMethod(methodName,String.class);
                            this.methodMapThreadLocal.get().put(methodName,method);
                        }

                        Object context = method.invoke(null,requestJson);
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("success",true);
                        jsonObject.put("resultCode",1000);
                        jsonObject.put("result",context);
                        System.out.println(jsonObject.toString());
                       responseJsonOK(ctx,req,jsonObject.toString());
                       return;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("success",false);
            jsonObject.put("resultCode",404);
            responseJsonOK(ctx,req,jsonObject.toString());
        }
    }

    /**
     * 响应HTTP的请求
     * @param ctx
     * @param req
     * @param jsonStr
     */
    private void responseJsonOK(ChannelHandlerContext ctx, FullHttpRequest req ,String jsonStr)
    {
        boolean keepAlive = HttpUtil.isKeepAlive(req);
        byte[] jsonByteByte = jsonStr.getBytes();
        FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(jsonByteByte));
        response.headers().set(CONTENT_TYPE, "text/json");
        response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());

        response.headers().set("Access-Control-Allow-Origin", "*");
        response.headers().set("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
        response.headers().set("Access-Control-Allow-Credentials", "true");
        response.headers().set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
        response.headers().setInt("Access-Control-Max-Age", 1209600);

        if (!keepAlive) {
            ctx.write(response).addListener(ChannelFutureListener.CLOSE);
        } else {
            response.headers().set(CONNECTION, KEEP_ALIVE);
            ctx.write(response);
        }
    }


    /**
     * 解析请求参数
     * @return 包含所有请求参数的键值对, 如果没有参数, 则返回空Map
     * @throws IOException
     */
    public static Map<String, String> parseUrl(FullHttpRequest fullReq) throws IOException {
        HttpMethod method = fullReq.method();
        Map<String, String> parmMap = new HashMap<String, String>();

        //解析路径参数
        QueryStringDecoder queryStringDecoder = new QueryStringDecoder(fullReq.uri());
        for (Map.Entry<String, List<String>> entry : queryStringDecoder.parameters().entrySet()) {
            parmMap.put(entry.getKey(), entry.getValue().get(0));
        }

        if (HttpMethod.POST == method) {
            // 是POST请求
            HttpPostRequestDecoder postRequestDecoder = new HttpPostRequestDecoder(fullReq);
            postRequestDecoder.offer(fullReq);

            List<InterfaceHttpData> parmList = postRequestDecoder.getBodyHttpDatas();

            for (InterfaceHttpData parm : parmList) {
                Attribute data = (Attribute) parm;
                parmMap.put(data.getName(), data.getValue());
            }
        }
        return parmMap;
    }

    private ThreadLocal<Map<String,Method>> methodMapThreadLocal = new ThreadLocal<Map<String, Method>>();
}
